/**
 * @file main.cpp
 * @author Scanagatta Mauro - Alberto Franco
 *
 * Contains program entry point.
 */


#include <cstdlib>
#include <iostream>
#include <vector>
#include <fstream>
#include <string>

#include "UpgmaAlgorithm.h"
#include "ClustalWSample.h"
#include "NewickTree.h"
#include "NewickTreeFactory.h"


/// Represent a pair <name, sequence> as in the FASTA format.
struct FastaPair {
    std::string name;     ///< The name of the protein sequence
    std::string sequence; ///< Actual protein sequence
};

void readFasta(std::vector<FastaPair>& sequences, std::string filename) 
{
    using namespace std;
    // Some variable declaration
    ifstream inData(filename.c_str());
    char     sequence[256];
    // Check file opening
    if (!inData) 
        throw "Error, could not find FASTA file";
    // Read first line
    inData.getline(sequence, 256, '\n');
    // Go down to the whole file.
    while(!inData.eof())
    {
        // New string to push
        if (sequence[0] == '>')
        {
            FastaPair newPair;
            newPair.name = string(sequence);
            sequences.push_back(newPair);
        }
        else // No new string. Attach to the old one
        {
            for (int i = 0; i < 256 &&  sequence[i] != 0; i++)
                sequences.back().sequence.push_back(sequence[i]);
        }
        inData.getline(sequence, 256, '\n');
    }
    inData.close();
}

void writeFasta(std::vector<FastaPair>& sequences, std::string filename)
{
    using namespace std;
    ofstream outData(filename.c_str());
    if (!outData)
        throw "Error! No write permission for FASTA file";
        
    for (size_t i = 0; i < sequences.size(); i++)
    {
        outData << ">" << sequences[i].name << endl;
        for (size_t j = 0; j < sequences[i].sequence.size(); j++)
        {
            outData << sequences[i].sequence[j];
            if ((j + 1) % 80) outData << endl;
        }
        outData << endl;
    }
}

void readSequences(vector<string> & sequences) {

    std::cout << "\t\t\t * Getting input sequences... * " << std::endl;

    // Leggi le N sequenze che costituiscono l'input di UPGMA

    char sequence[256];
    // Stream di input file
    std::ifstream indata;

    indata.open("sequences.fasta"); // opens the file
    if(!indata) { // file couldn't be opened
        throw "Error: file could not be opened";
    }

    indata.getline(sequence, 256, '\n');
    while ( !indata.eof() ) { // keep reading until end-of-file
        sequences.push_back(sequence);
        indata.getline(sequence, 256, '\n');
    }
    indata.close();
}

/**
 * @brief Con questa classe, viene testato il funzionamento
 * delle classi UPGMA e ClustalWDummy
 */
int main (int argc, char const *argv[])
{
	try
	{
            // Vettore delle sequenze da allineare
            std::vector<std::string> sequences(0);
            readSequences(sequences);
            
            // Stampa le stringe prese
            std::cout << "Printing getted input sequences... " << std::endl;
            for (unsigned int i = 0; i < sequences.size(); i++)
            {
                std::cout << "   Sequence #" << i << '\t' << sequences[i] << std::endl;
            }

            // invoke upgma
            Biopool::UpgmaAlgorithm upgma(sequences);
            // TODO: fa ritornare string con serializzazione
            Biopool::NewickTree evolTree = upgma.execute();
            
            string               treeString = Biopool::NewickTreeFactory::serialize(evolTree);
            cout << treeString << endl;
            Biopool::NewickTree* verifyTree = Biopool::NewickTreeFactory::deserialize(treeString);
            string               testString = Biopool::NewickTreeFactory::serialize(*verifyTree);
            
            cout << testString << endl;
            // cout << "\n Evolutionary Tree calculated by UPGMA: \n" << evolTree << std::endl;

            // invoke multiple alignment
            Biopool::ClustalWSample clustal(evolTree, sequences);
            std::vector<std::string> fastaAlignment = clustal.execute();

            std::cout << "\n FASTA format by clustalW: \n" << std::endl;

            for (unsigned int i = 0; i < fastaAlignment.size(); i++)
            {
                std::cout << "   Sequence #" << i << '\t' << fastaAlignment[i] << std::endl;
            }
            
	} catch( char const * str ) {
            std::cout << "\nException raised: " << str << std::endl;
	} 
    // catch(std::exception e)	{
    //         std::cout << "\n>>>EXCEPTION: " << e.what() << std::endl;
	// }

	return 0;
}

